﻿using CIS.Common.Dtos;
using CIS.Common.Grpc;
using CIS.Device.Common.Events;
using CIS.Device.Models;
using CIS.Device.PLCAction;
using Newtonsoft.Json;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CIS.Device.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private GrpcClient _grpcClient;
        private ConcurrentDictionary<string,Type> PlcActions = new ConcurrentDictionary<string, Type>();

        public MainWindowViewModel(IEventAggregator eventAggregator)
        {
            InitGrpc();
            GetPLCEvents();
            Log = new LogInfo();
            eventAggregator.GetEvent<ReportEvent<GrpcMessage>>().Subscribe(OnSend);
        }

        #region 属性
        private LogInfo log;
        

        public LogInfo Log
        {
            get { return log; }
            set { log = value; RaisePropertyChanged(nameof(Log)); }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 初始化 Grpc 连接
        /// </summary>
        private void InitGrpc()
        {
            Task.Run(() =>
            {
                _grpcClient = new GrpcClient("EQLinker");
                if (_grpcClient.Start().Result)
                {
                    Log.FormatMsg("Server Is Connected");
                    _grpcClient.StartListen();
                }
                _grpcClient.OnRequestAsync += OnRequest;
            });
        }

        /// <summary>
        /// 获取 PLC 事件集合
        /// </summary>
        private void GetPLCEvents()
        {
            var assembly = typeof(IPLCEvent).Assembly;

            var types = assembly.GetTypes();
            foreach (var t in types)
            {
                if (typeof(IPLCEvent).IsAssignableFrom(t))
                {
                    var atr = t.GetCustomAttribute<PLCAttribute>(true);
                    if (atr != null)
                    {
                        PlcActions[atr.ActionName] = t;
                    }
                }
            }
        }

        /// <summary>
        /// Client 向 Server 发送消息处理方法
        /// </summary>
        /// <param name="msg"></param>
        private void OnSend(GrpcMessage msg)
        {
            Log.FormatMsg("↑ Send  " + msg.Name);
            _grpcClient.SendAsync(msg);
        }

        /// <summary>
        /// Client 收到 Server 消息处理方法
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private async Task<GrpcMessage> OnRequest(GrpcMessage message)
        {
            var eventName = message.Name?.Replace("Dto", "");
            Type? plcAction = null;
            var result = PlcActions.TryGetValue(eventName, out plcAction);
            if (result && plcAction != null)
            {
                var action = Activator.CreateInstance(plcAction) as IPLCEvent;
                action.ReceiveDataFromServer(message.Data);
                Log.FormatMsg("↑ Received  " + eventName);
                if (message.IsRequest)
                {
                    var reply = action.SendDataToServer();
                    message.Data = JsonConvert.SerializeObject(reply);
                    var report = action.DataReport();
                    GrpcMessage msg = new GrpcMessage();
                    msg.Name = (report as IDtoEvent).EventName;
                    msg.Data = JsonConvert.SerializeObject(report);
                    this.OnSend(msg);
                    Log.FormatMsg("↓ Reply  " + eventName);
                }
            }
            return message;
        }
        #endregion
    }
}
